#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
文件同步软件打包脚本
使用PyInstaller将Python应用打包成exe文件
"""

import os
import sys
import subprocess
import shutil
from pathlib import Path
import argparse

try:
    from PIL import Image
    PIL_AVAILABLE = True
except ImportError:
    PIL_AVAILABLE = False

def check_dependencies():
    """检查依赖是否已安装"""
    missing_deps = []
    
    # 检查PyInstaller
    try:
        import PyInstaller
        print("✓ PyInstaller已安装")
    except ImportError:
        print("✗ PyInstaller未安装")
        missing_deps.append('pyinstaller')
    
    # 检查Pillow (用于图标转换)
    if PIL_AVAILABLE:
        print("✓ Pillow已安装")
    else:
        print("✗ Pillow未安装 (图标转换需要)")
        missing_deps.append('pillow')
    
    return missing_deps

def install_dependencies(deps):
    """安装缺失的依赖"""
    if not deps:
        return True
        
    print(f"正在安装依赖: {', '.join(deps)}...")
    try:
        subprocess.check_call([sys.executable, "-m", "pip", "install"] + deps)
        print("✓ 依赖安装成功")
        return True
    except subprocess.CalledProcessError:
        print("✗ 依赖安装失败")
        return False

def convert_png_to_ico(png_path, ico_path=None):
    """将PNG图标转换为ICO格式"""
    if not PIL_AVAILABLE:
        print("✗ Pillow未安装，无法转换图标格式")
        return None
        
    try:
        if not os.path.exists(png_path):
            print(f"✗ 图标文件不存在: {png_path}")
            return None
            
        if ico_path is None:
            ico_path = os.path.splitext(png_path)[0] + '.ico'
            
        # 打开PNG图像
        img = Image.open(png_path)
        
        # 转换为RGBA模式（支持透明度）
        if img.mode != 'RGBA':
            img = img.convert('RGBA')
            
        # 创建多种尺寸的图标（Windows标准）
        sizes = [(16, 16), (32, 32), (48, 48), (64, 64), (128, 128), (256, 256)]
        
        # 保存为ICO格式
        img.save(ico_path, format='ICO', sizes=sizes)
        print(f"✓ 图标转换成功: {ico_path}")
        return ico_path
        
    except Exception as e:
        print(f"✗ 图标转换失败: {e}")
        return None

def find_icon_file():
    """自动查找项目目录中的图标文件"""
    icon_extensions = ['.png', '.ico', '.jpg', '.jpeg']
    icon_names = ['icon', 'logo', 'app_icon', 'application']
    
    # 在当前目录查找
    for name in icon_names:
        for ext in icon_extensions:
            icon_path = f"{name}{ext}"
            if os.path.exists(icon_path):
                print(f"✓ 找到图标文件: {icon_path}")
                return icon_path
                
    # 在assets或icons目录查找
    for subdir in ['assets', 'icons', 'images']:
        if os.path.exists(subdir):
            for name in icon_names:
                for ext in icon_extensions:
                    icon_path = os.path.join(subdir, f"{name}{ext}")
                    if os.path.exists(icon_path):
                        print(f"✓ 找到图标文件: {icon_path}")
                        return icon_path
    
    return None

def prepare_icon(icon_path):
    """准备图标文件（如果是PNG则转换为ICO）"""
    if not icon_path:
        return None
        
    if not os.path.exists(icon_path):
        print(f"✗ 指定的图标文件不存在: {icon_path}")
        return None
        
    # 如果是ICO文件，直接使用
    if icon_path.lower().endswith('.ico'):
        print(f"✓ 使用ICO图标: {icon_path}")
        return icon_path
        
    # 如果是PNG文件，转换为ICO
    if icon_path.lower().endswith('.png'):
        ico_path = convert_png_to_ico(icon_path)
        return ico_path
        
    # 其他格式，尝试转换
    print(f"⚠ 尝试转换图标格式: {icon_path}")
    ico_path = convert_png_to_ico(icon_path)
    return ico_path

def create_spec_file(icon_path=None):
    """创建PyInstaller规格文件"""
    # 处理图标路径
    icon_line = "icon=None," if not icon_path else f"icon='{icon_path}',"
    
    # 准备数据文件列表（包含图标文件）
    datas_list = []
    
    # 添加图标文件到数据文件中
    icon_files = ['logo.png', 'logo.ico', 'icon.png', 'icon.ico']
    for icon_file in icon_files:
        if os.path.exists(icon_file):
            datas_list.append(f"('{icon_file}', '.')")
            print(f"✓ 将图标文件包含在打包中: {icon_file}")
    
    # 添加配置文件
    config_files = ['folder_history.json', 'exclude_rules.json', 'git_config.json']
    for config_file in config_files:
        if os.path.exists(config_file):
            datas_list.append(f"('{config_file}', '.')")
    
    datas_str = '[' + ', '.join(datas_list) + ']' if datas_list else '[]'
    
    spec_content = f'''
# -*- mode: python ; coding: utf-8 -*-

block_cipher = None

a = Analysis(
    ['file_sync.py'],
    pathex=[],
    binaries=[],
    datas={datas_str},
    hiddenimports=['watchdog.observers.polling'],
    hookspath=[],
    hooksconfig={{}},
    runtime_hooks=[],
    excludes=[],
    win_no_prefer_redirects=False,
    win_private_assemblies=False,
    cipher=block_cipher,
    noarchive=False,
)

pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)

exe = EXE(
    pyz,
    a.scripts,
    a.binaries,
    a.zipfiles,
    a.datas,
    [],
    name='文件同步工具',
    debug=False,
    bootloader_ignore_signals=False,
    strip=False,
    upx=True,
    upx_exclude=[],
    runtime_tmpdir=None,
    console=False,
    disable_windowed_traceback=False,
    argv_emulation=False,
    target_arch=None,
    codesign_identity=None,
    entitlements_file=None,
    {icon_line}
)
'''
    
    with open('file_sync.spec', 'w', encoding='utf-8') as f:
        f.write(spec_content)
    print("✓ 已创建PyInstaller规格文件")
    if icon_path:
        print(f"✓ 已设置图标: {icon_path}")

def build_exe():
    """构建exe文件"""
    print("开始构建exe文件...")
    try:
        # 使用spec文件构建
        subprocess.check_call(["pyinstaller", "--clean", "file_sync.spec"])
        print("✓ exe文件构建成功")
        return True
    except subprocess.CalledProcessError as e:
        print(f"✗ 构建失败: {e}")
        return False

def cleanup():
    """清理临时文件"""
    print("清理临时文件...")
    dirs_to_remove = ['build', '__pycache__']
    files_to_remove = ['file_sync.spec']
    
    for dir_name in dirs_to_remove:
        if os.path.exists(dir_name):
            shutil.rmtree(dir_name)
            print(f"✓ 已删除 {dir_name} 目录")
    
    for file_name in files_to_remove:
        if os.path.exists(file_name):
            os.remove(file_name)
            print(f"✓ 已删除 {file_name} 文件")

def copy_resources():
    """复制资源文件到dist目录"""
    dist_dir = Path('dist')
    if not dist_dir.exists():
        print("✗ dist目录不存在")
        return
    
    # 复制README文件
    if os.path.exists('README.md'):
        shutil.copy2('README.md', dist_dir)
        print("✓ 已复制README.md")
    
    # 复制配置文件
    config_files = ['folder_history.json', 'exclude_rules.json']
    for config_file in config_files:
        if os.path.exists(config_file):
            shutil.copy2(config_file, dist_dir)
            print(f"✓ 已复制{config_file}")
        else:
            print(f"⚠ {config_file}不存在，将在运行时创建")
    
    print("✓ 资源文件复制完成")

def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(
        description='文件同步软件打包工具',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog='''
使用示例:
  python build_exe.py                    # 自动查找图标文件
  python build_exe.py --icon logo.png    # 使用指定的PNG图标
  python build_exe.py --icon app.ico     # 使用指定的ICO图标
  python build_exe.py --no-cleanup       # 打包后不清理临时文件
        '''
    )
    
    parser.add_argument(
        '--icon', '-i',
        type=str,
        help='指定图标文件路径（支持PNG、ICO、JPG格式）'
    )
    
    parser.add_argument(
        '--no-cleanup',
        action='store_true',
        help='打包完成后不清理临时文件'
    )
    
    parser.add_argument(
        '--auto-install',
        action='store_true',
        help='自动安装缺失的依赖包'
    )
    
    return parser.parse_args()

def main():
    """主函数"""
    # 解析命令行参数
    args = parse_arguments()
    
    print("=" * 60)
    print("文件同步软件打包工具")
    print("=" * 60)
    
    # 检查当前目录是否包含file_sync.py
    if not os.path.exists('file_sync.py'):
        print("✗ 未找到file_sync.py文件，请在正确的目录下运行此脚本")
        return
    
    # 检查并安装依赖
    missing_deps = check_dependencies()
    if missing_deps:
        if args.auto_install:
            if not install_dependencies(missing_deps):
                print(f"请手动安装依赖: pip install {' '.join(missing_deps)}")
                return
        else:
            print(f"请安装缺失的依赖: pip install {' '.join(missing_deps)}")
            print("或使用 --auto-install 参数自动安装")
            return
    
    # 处理图标
    icon_path = None
    if args.icon:
        # 使用指定的图标
        icon_path = prepare_icon(args.icon)
        if not icon_path:
            print("⚠ 指定的图标无法使用，将不使用图标")
    else:
        # 自动查找图标
        found_icon = find_icon_file()
        if found_icon:
            icon_path = prepare_icon(found_icon)
            if not icon_path:
                print("⚠ 找到的图标无法使用，将不使用图标")
        else:
            print("⚠ 未找到图标文件，将不使用图标")
            print("提示: 可以将图标文件命名为 icon.png 或 logo.png 放在项目目录中")
    
    # 创建规格文件
    create_spec_file(icon_path)
    
    # 构建exe
    if build_exe():
        # 复制资源文件
        copy_resources()
        
        print("\n" + "=" * 60)
        print("✓ 打包完成！")
        print("exe文件位置: dist/文件同步工具.exe")
        if icon_path:
            print(f"图标文件: {icon_path}")
        print("=" * 60)
        
        # 清理临时文件
        if not args.no_cleanup:
            response = input("\n是否清理临时文件？(y/n): ")
            if response.lower() in ['y', 'yes', '是']:
                cleanup()
        else:
            print("\n⚠ 跳过清理临时文件")
    else:
        print("\n✗ 打包失败")

if __name__ == "__main__":
    main()